package com.atwisdom.star.service.business;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.atwisdom.star.common.util.JsonUtil;
import com.atwisdom.star.common.util.SpringContextUtil;
import com.atwisdom.star.common.util.UuidTool;
import com.atwisdom.star.core.dao.pojo.modelClass.hier.HierInstance;
import com.atwisdom.star.core.dao.pojo.modelClass.tank.TankInstance;
import com.atwisdom.star.core.dsl.modelClass.hier.Impl.HierInstanceDslServiceImpl;
import com.atwisdom.star.core.dsl.modelClass.resource.Impl.ResourceInstanceDslServiceImpl;
import com.atwisdom.star.core.dsl.modelClass.tank.Impl.TankInstanceDslServiceImpl;
import com.atwisdom.star.exception.pojo.BusinessException;
import com.atwisdom.star.service.pojo.BasicStatus;
import com.atwisdom.star.service.status.TankStatus;
import com.atwisdom.star.service.util.ArithUtil;
import lombok.Data;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @ClassName: Tank 桶
 * @ Description:桶相关的处理
 * @author:王红艳
 * @date: 2024/05/25 14:16
 */
@Service
@Data
public class Tank {
    private final TankInstanceDslServiceImpl tankService = SpringContextUtil.getBean(TankInstanceDslServiceImpl.class);
    private final ResourceInstanceDslServiceImpl recordService  = SpringContextUtil.getBean(ResourceInstanceDslServiceImpl.class);
    private final HierInstanceDslServiceImpl hierInstanceDslServiceImpl = SpringContextUtil.getBean(HierInstanceDslServiceImpl.class);

    private TankInstance tank;
    private JSONObject tankJson;
    private BigDecimal totalCapacity;
    private BigDecimal usedCapacity;
    private BigDecimal restCapacity;
    private List<JSONObject> inputRecords;
    private List<JSONObject> outputRecords;

    private String totalCapacityName = "totalCapacity";
    private String usedCapacityName = "usedCapacity";
    private String restCapacityName = "restCapacity";
    private final String recordModelName = "resource";
    private final String recordClassName = "StorehouseTankRecords";
    private final String recordTypeName = "storehouse";
    private final String tankModelName = "tank";
    private final String tankClassName = "Tank";
    private final String tankTypeName = "tank";
    private final String inputName = "入库记录";
    private final String outputName = "出库记录";

    /**
     * 更新桶状态
     * @param id 实例id
     * @param status 状态
     */
    public void updateTankRunStatus(Long id,String status){
        TankStatus tankStatus = new TankStatus(id);
        tankStatus.setUpdateStatus(tankStatus.getRunStatusKey(),status);
        tankStatus.next(tankStatus.checkStatus(BasicStatus.TANK_STATUS_ENABLE));
    }

    /**
     * 根据名称获取父级id
     * @param name 父级名称
     * @return
     */
    private String getParentIdByName(String name){
        List<HierInstance> hierList = tank.getHierInstances().stream().filter(hierInstance -> name.equals(hierInstance.getName())).collect(Collectors.toList());
        if(CollectionUtil.isEmpty(hierList)){
            throw new BusinessException("父级"+name+"不存在");
        }
        return hierList.get(0).getNodeId();
    }

    /**
     * 获取子级实例
     * @param parentId 父级id
     * @return
     */
    private List<JSONObject> getHierInstancesLinkJson(String parentId) {
        return tank.getHierInstances().stream()
                .filter(hierInstance -> parentId.equals(hierInstance.getParentId())&&null!=hierInstance.getLinkId())
                .map(hierInstance -> recordService.queryById(hierInstance.getLinkId()))
                .collect(Collectors.toList());
    }

    /**
     * 根据id初始化桶
     * @param id 桶id
     */
    public void setTank(Long id){
        if(null==id){
            throw new BusinessException("tank id 不能为空");
        }
        setTank(tankService.queryById(id));
    }

    /**
     * 根据桶实例初始化
     * @param tank 桶实例
     */
    public void setTank(TankInstance tank){
        if(null==tank){
            throw new BusinessException("tank 不能为空");
        }
        this.tank = tank;
        this.inputRecords = getHierInstancesLinkJson(getParentIdByName(inputName));
        this.outputRecords = getHierInstancesLinkJson(getParentIdByName(outputName));
        setTank(tankService.getTankInsJsonObjectList(Arrays.asList(tank)).get(0));
    }

    /**
     * 根据桶json初始化
     * @param tankJson 桶json
     */
    private void setTank(JSONObject tankJson){
        this.tankJson = tankJson;
        if(null== JsonUtil.get(this.tankJson,"values."+totalCapacityName)){
            throw new BusinessException("总重量不能为空");
        }
        if(null== JsonUtil.get(this.tankJson,"values."+usedCapacityName)){
            throw new BusinessException("使用重量不能为空");
        }
        if(null== JsonUtil.get(this.tankJson,"values."+restCapacityName)){
            throw new BusinessException("剩余重量不能为空");
        }
        this.totalCapacity = ArithUtil.doubleRoundToBigDecimal(Double.valueOf(JsonUtil.get(this.tankJson,"values."+totalCapacityName).toString()));
        this.usedCapacity = ArithUtil.doubleRoundToBigDecimal(Double.valueOf(JsonUtil.get(this.tankJson,"values."+usedCapacityName).toString()));
        this.restCapacity = ArithUtil.doubleRoundToBigDecimal(Double.valueOf(JsonUtil.get(this.tankJson,"values."+restCapacityName).toString()));
        if(!this.totalCapacity.subtract(this.usedCapacity).subtract(this.restCapacity).equals(BigDecimal.ZERO)){
            throw new BusinessException("总重量不等于使用重量和剩余重量的和");
        }
    }

    /**
     * 入库
     * @param id 库位id
     * @param code 库位编码
     * @param name 库位名称
     */
    public void inputBound(Long id,String code,String name){
        JSONObject recordJson =  addRecord(id, code, name,"入库",null);
        hierInstanceDslServiceImpl.addChild(JsonUtil.buildJson(new Object[]{"containerModel",tankModelName,"containerId",this.tank.getId(),"parentId",getParentIdByName(inputName),"linkId",recordJson.getLong("id"),"values",JsonUtil.buildJson(new Object[]{"linkId",recordJson.getLong("id")})}));
        updateTankRunStatus(this.tankJson.getLong("id"),BasicStatus.TANK_RUN_STATUS_OCCUPY);
    }

    /**
     * 新增出入库记录
     * @param id 仓库id
     * @param code 仓库编码
     * @param name 仓库名称
     * @param type 记录类型：出库，入库
     * @param weight 重量
     * @return
     */
    private JSONObject addRecord(Long id, String code, String name,String type,Double weight) {
        JSONObject values = JsonUtil.buildJson(new Object[]{"storehouseId", id,"storehouseCode", code,"storehouseName", name,"type",type,"tankId",this.tank.getId(),"weight",(null==weight?this.restCapacity:weight)});
        return recordService.add(recordTypeName,recordClassName, UuidTool.getUUID32(),values);
    }

    /**
     * 出库
     * @param id 库位id
     * @param code 库位编码
     * @param name 库位名称
     */
    public void outBound(Long id,String code,String name){
        /*this.usedCapacity = ArithUtil.bigDecimalAddToBigDecimal(this.usedCapacity,this.restCapacity);
        this.restCapacity = BigDecimal.ZERO;
        updateTank(new JSONObject());*/
        JSONObject recordJson =  addRecord(id, code, name,"出库",null);
        hierInstanceDslServiceImpl.addChild(JsonUtil.buildJson(new Object[]{"containerModel",tankModelName,"containerId",this.tank.getId(),"parentId",getParentIdByName(outputName),"linkId",recordJson.getLong("id"),"values",JsonUtil.buildJson(new Object[]{"linkId",recordJson.getLong("id")})}));
        updateTankRunStatus(this.tankJson.getLong("id"), BasicStatus.TANK_RUN_STATUS_FREE);
    }

    /**
     * 领用
     * @param weight 重量
     */
    public void pick(BigDecimal weight){
        checkWeight(weight);
        if(this.restCapacity.subtract(weight).compareTo(BigDecimal.ZERO)<0){
            throw new BusinessException("剩余重量为："+this.restCapacity+",使用重量为："+weight+",使用重量不能大于剩余重量");
        }
        this.usedCapacity = ArithUtil.bigDecimalAddToBigDecimal(this.usedCapacity,weight);
        this.restCapacity = ArithUtil.bigDecimalSubToBigDecimal(this.restCapacity,weight);
        updateTank(new JSONObject());
    }

    /**
     * 退回
     * @param weight 重量
     */
    public void returnWeight(BigDecimal weight){
        checkWeight(weight);
        if(this.usedCapacity.subtract(weight).compareTo(BigDecimal.ZERO)<0){
            throw new BusinessException("使用重量为："+this.restCapacity+",退回重量为："+weight+",退回重量不能大于使用重量");
        }
//        this.totalCapacity = ArithUtil.bigDecimalAddToBigDecimal(this.restCapacity,weight);
        this.usedCapacity = ArithUtil.bigDecimalSubToBigDecimal(this.usedCapacity,weight);
        this.restCapacity = ArithUtil.bigDecimalAddToBigDecimal(this.restCapacity,weight);
        updateTank(new JSONObject());
    }

    /**
     * 更新桶实例数据
     * @param values
     */
    public void updateTank(JSONObject values) {
        this.tankJson.getJSONObject("values").putAll(values);
        this.tankJson.getJSONObject("values").put("totalCapacity",this.totalCapacity);
        this.tankJson.getJSONObject("values").put("usedCapacity",this.usedCapacity);
        this.tankJson.getJSONObject("values").put("restCapacity",this.restCapacity);
        setTank(tankService.updateById(this.tankJson));
    }

    /**
     * 校验重量
     * @param weight
     */
    private void checkWeight(BigDecimal weight) {
        if(null==weight){
            throw new BusinessException("重量不能为空");
        }
    }
}
